package com.mzwise.tunnel.service;

import cn.hutool.json.JSONObject;
import com.mzwise.tunnel.service.Configs;
import com.mzwise.tunnel.wx.v3.WxV3Client;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.nio.charset.Charset;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Random;
import java.util.UUID;

/**
 *媒体相关工具
 */
public class V3MaterialService {

    public V3MaterialService(Configs configs) {
        if (configs.getWxV3Client() != null) {
            try {
                wxV3Client = configs.getWxV3Client();
                System.out.println("tunnel:微信v3媒体通道开启");
            } catch (Exception e) {
                System.out.println("tunnel:微信v3媒体通道开启错误");
                e.printStackTrace();
            }
        }
    }

    private WxV3Client wxV3Client;

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    /**
     * 上传图片
     * @param img
     * @return
     * @throws Exception
     */
    public String imgMediaId(String img) throws Exception {
        try {
            //商户号
            String mchid = wxV3Client.getMerchantId();
            //证书序列号
            String serial_no = wxV3Client.getSerialNo();
            //商户私钥（拷贝apiclient_key.pem文件里-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的内容）
            String rsaPrivateKey = wxV3Client.getPrivateKey();
            //微信支付平台公钥
            String rsaPublicKeyFile = "";
            //时间戳
            String timestamp = Long.toString(System.currentTimeMillis() / 1000);
            //随机数
            String nonce_str = generateNonceStr();
//            //随机数
//            String nonce_str = "4547414785";
            //图片文件
//            String filePath = "D:/juh.png";//文件路径
            File file = new File(img);
            String filename = file.getName();//文件名
            String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256

            //拼签名串
            StringBuffer sb = new StringBuffer();
            sb.append("POST").append("\n");
            sb.append("/v3/merchant/media/upload").append("\n");
            sb.append(timestamp).append("\n");
            sb.append(nonce_str).append("\n");
            sb.append("{\"filename\":\"" + filename + "\",\"sha256\":\"" + fileSha256 + "\"}").append("\n");
            System.out.println("签名原串:" + sb.toString());

            //计算签名
            String sign = new String(Base64.encodeBase64(signRSA(sb.toString(), rsaPrivateKey)));
            System.out.println("签名sign值:" + sign);

            //拼装http头的Authorization内容
            String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + mchid + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + serial_no + "\"";
            System.out.println("authorization值:" + authorization);

            //接口URL
            String url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);

            //设置头部
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-Type", "multipart/form-data");
            httpPost.addHeader("Authorization", authorization);

            //创建MultipartEntityBuilder
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
            //设置boundary
            multipartEntityBuilder.setBoundary(UUID.randomUUID().toString());
            multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
            //设置meta内容
            multipartEntityBuilder.addTextBody("meta", "{\"filename\":\"" + filename + "\",\"sha256\":\"" + fileSha256 + "\"}", ContentType.APPLICATION_JSON);
            //设置图片内容
            multipartEntityBuilder.addBinaryBody("file", file, ContentType.create("image/jpg"), filename);
            //放入内容
            httpPost.setEntity(multipartEntityBuilder.build());

            //获取返回内容
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);
            JSONObject object = new JSONObject(rescontent);
            String mediaId=object.getStr("media_id");
            return mediaId;
        } catch (Exception e) {
            System.out.println("发送POST请求异常！" + e);
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 敏感信息加密
     * @param message
     * @param certificate
     * @return
     * @throws IllegalBlockSizeException
     * @throws IOException
     */
    public static String rsaEncryptOAEP(String message, X509Certificate certificate) throws IllegalBlockSizeException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
            certificate.getPublicKey();
            byte[] data = message.getBytes("utf-8");
            byte[] cipherdata = cipher.doFinal(data);
            return java.util.Base64.getEncoder().encodeToString(cipherdata);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("无效的证书", e);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
        }
    }

    public static byte[] InputStreamTOByte (InputStream in) throws IOException {

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);

        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }

    public static byte[] signRSA (String data, String priKey) throws Exception {
        //签名的类型
        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

    }

    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
}
